import { ref, unref, watch, nextTick } from "vue";
import type { FormActionType, FormProps, FormSchema } from "../types";

export default function useForm(props?: any) {
  const formAction: any = ref(null);
  const loadedRef = ref(false);

  function register(instance: FormActionType) {
    if (unref(loadedRef) && instance === unref(formAction)) {
      return;
    }

    formAction.value = instance;
    loadedRef.value = true;

    // 监听 props， 若props改变了
    // 则使用 form 实例调用内部的 setProps 方法将新的props设置到form组件内部
    watch(
      () => props,
      () => {
        if (props) {
          instance.setProps(props);
        }
      },
      { immediate: true, deep: true }
    );
  }

  async function getForm() {
    const form = unref(formAction);
    if (!form) {
      throw new Error(
        "The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!"
      );
    }
    await nextTick();
    return form as FormActionType;
  }

  const methods: FormActionType = {
    async setProps(formProps: Partial<FormProps>) {
      const form = await getForm();
      form.setProps(formProps);
    },
    async validate() {
      const form = await getForm();
      form.validate();
    },
    async validateField(
      props: string | string[],
      callback: (err: string) => void
    ) {
      const form = await getForm();
      form.validateField(props, callback);
    },
    async resetFields() {
      const form = await getForm();
      form.resetFields();
    },
    async clearValidate() {
      const form = await getForm();
      form.clearValidate();
    },
    async scrollToField(prop: string) {
      const form = await getForm();
      form.scrollToField(prop);
    },
    async getValue() {
      const form = await getForm();
      const r = await form.validate();
      return r;
    },
    async setFiledsValue(props) {
      const form = await getForm();
      form.setFiledsValue(props);
    },
    async updateSchemaByField(k, v) {
      const form = await getForm();
      form.updateSchemaByField(k, v);
    },
    async updateSchema(v) {
      const form = await getForm();
      form.updateSchema(v);
    },
    async removeSchemaByField(k) {
      const form = await getForm();
      form.removeSchemaByField(k);
    },
    async appendSchemaByField(schema: FormSchema, prefixField, first = false) {
      const form = await getForm();
      form.appendSchemaByField(schema, prefixField, first);
    },
  };

  return [register, methods] as any;
}
